/**
 * 按开发进度文档序号顺序检查所有题型
 * 运行：node math-academy/scripts/verify-all-topics.js
 */

const fs = require('fs');
const path = require('path');

const ROOT = path.join(__dirname, '..', '..');
const QUESTIONS_DIR = path.join(ROOT, 'questions');
const PRIMARY_DIR = path.join(QUESTIONS_DIR, 'primary-school');
const MIDDLE_DIR = path.join(QUESTIONS_DIR, 'middle-school');

// 按开发进度文档的序号顺序
const TOPIC_ORDER = [
  // 小学奥数题型 (35个)
  '鸡兔同笼', '和差倍问题', '年龄问题', '平均数问题', '行程问题',
  '工程问题', '盈亏问题', '植树问题', '数论基础', '几何计算',
  '计数原理', '分数应用题', '小数应用题', '百分数应用题', '比例应用题',
  '容斥原理', '逻辑推理', '抽屉原理', '数字谜题', '周期问题',
  '归一问题', '牛吃草问题', '时钟问题', '日历问题', '图形计数',
  '找规律', '数列问题', '面积计算', '体积计算', '空间想象',
  '概率统计', '排列组合', '数学游戏', '数学思维', '综合应用',
  // 初中数学题型 (22个)
  '有理数运算', '整式运算', '因式分解', '分式运算', '二次根式',
  '一元一次方程', '二元一次方程组', '一元二次方程', '分式方程', '不等式',
  '函数基础', '一次函数', '反比例函数', '二次函数', '几何证明',
  '三角形', '四边形', '圆', '相似', '解直角三角形',
  '统计', '概率'
];

function read(file) { return fs.readFileSync(file, 'utf-8'); }
function write(file, content) { fs.writeFileSync(file, content, 'utf-8'); }
function s(str){ return JSON.stringify(String(str)).slice(1,-1); }
function near(a,b){ return Math.abs(Number(a)-Number(b)) < 1e-6; }
function round(v){ return Math.round(v*1000)/1000; }

function extractExportedArray(tsContent) {
  const m = tsContent.match(/export\s+const\s+([A-Za-z0-9_\u4e00-\u9fa5]+)\s*=\s*(\[[\s\S]*?\]);/m);
  if (!m) return null;
  return { name: m[1], array: m[2] };
}

function parseArray(lit) { try { return eval(`(${lit})`); } catch { return null; } }

function rebuild(name, arr, originalHeader) {
  const objs = arr.map(q => {
    const ansArr = Array.isArray(q.answer) ? q.answer : [q.answer];
    const ans = ansArr.map(v => typeof v === 'number' ? v : `"${s(v)}"`).join(', ');
    const fields = [
      `stem: "${s(q.stem)}"`,
      `difficulty: ${q.difficulty}`,
      `answer: [${ans}]`,
      q.hint1 ? `hint1: "${s(q.hint1)}"` : null,
      q.hint2 ? `hint2: "${s(q.hint2)}"` : null,
      q.solution ? `solution: "${s(q.solution)}"` : `solution: ""`,
    ].filter(Boolean).join(', ');
    return `  { ${fields} }`;
  }).join(',\n');
  const header = (originalHeader || '').split('\n')[0] || `// 由脚本 verify-all-topics.js 重写`;
  return `${header}\nexport const ${name} = [\n${objs}\n];\n\nexport default ${name};\n`;
}

// ========= 数学验证器 =========

// 1. 鸡兔同笼
function solveChickenRabbit(stem){
  const m = stem.match(/共有头(\d+)个.*?脚(\d+)只/);
  if(!m) return null;
  const H=+m[1], F=+m[2];
  const c=(4*H-F)/2, r=H-c;
  if(Number.isInteger(c)&&Number.isInteger(r)&&c>=0&&r>=0) return {ok:true,c,r,H,F};
  return {ok:false, reason:'数据不合理'};
}

// 2. 和差倍问题
function verifySumDiff(stem, answer){
  const sum = stem.match(/两数之和[是为](\d+(?:\.\d+)?)|和[是为](\d+(?:\.\d+)?)/);
  const diff = stem.match(/两数之差[是为](\d+(?:\.\d+)?)|差[是为](\d+(?:\.\d+)?)|大数比小数多(\d+(?:\.\d+)?)/);
  if(sum && diff){
    const S = parseFloat(sum[1] || sum[2]);
    const D = parseFloat(diff[1] || diff[2] || diff[3]);
    const big = (S + D) / 2;
    const small = (S - D) / 2;
    if(Array.isArray(answer) && answer.length >= 2){
      if(near(answer[0], big) && near(answer[1], small)) return {ok:true};
      if(near(answer[0], small) && near(answer[1], big)) return {ok:true};
      return {ok:false, fix:[round(big), round(small)]};
    }
  }
  
  const times = stem.match(/大数是小数的(\d+(?:\.\d+)?)倍|甲是乙的(\d+(?:\.\d+)?)倍/);
  const sum2 = stem.match(/两数之和[是为](\d+(?:\.\d+)?)|和[是为](\d+(?:\.\d+)?)|一共[是为](\d+(?:\.\d+)?)/);
  if(times && sum2){
    const N = parseFloat(times[1] || times[2]);
    const S = parseFloat(sum2[1] || sum2[2] || sum2[3]);
    const small = S / (N + 1);
    const big = S - small;
    if(Array.isArray(answer) && answer.length >= 2){
      if(near(answer[0], big) && near(answer[1], small)) return {ok:true};
      if(near(answer[0], small) && near(answer[1], big)) return {ok:true};
      return {ok:false, fix:[round(big), round(small)]};
    }
  }
  
  return null;
}

// 4. 平均数问题
function verifyAverage(stem, answer){
  const total = stem.match(/总[和共](?:是|为)?(\d+(?:\.\d+)?)|一共(?:是|为)?(\d+(?:\.\d+)?)/);
  const count = stem.match(/(\d+)(?:个|人|次|天)/);
  const askAvg = /平均|每(?:个|人|次|天)/.test(stem);
  if(total && count && askAvg){
    const T = parseFloat(total[1] || total[2]);
    const C = parseFloat(count[1]);
    const exp = T / C;
    return near(answer[0], exp) ? {ok:true} : {ok:false, fix:[round(exp)]};
  }
  
  const avg = stem.match(/平均(?:每(?:个|人|次|天))?(?:是|为)?(\d+(?:\.\d+)?)/);
  const count2 = stem.match(/(\d+)(?:个|人|次|天)/);
  const askTotal = /总[和共]|一共/.test(stem);
  if(avg && count2 && askTotal){
    const A = parseFloat(avg[1]);
    const C = parseFloat(count2[1]);
    const exp = A * C;
    return near(answer[0], exp) ? {ok:true} : {ok:false, fix:[round(exp)]};
  }
  
  return null;
}

// 5. 行程问题 + 6. 工程问题（通用速率-时间-数量）
function verifyDistanceLike(stem, answer){
  const v1 = stem.match(/每小时(\d+(?:\.\d+)?)公里|速度是每小时(\d+(?:\.\d+)?)/);
  const t1 = stem.match(/([\d.]+)小时/);
  const askDist = /多少公里|行了多少|一共.*?多少[米公里]/.test(stem);
  if(v1 && t1 && askDist){
    const v = parseFloat(v1[1] || v1[2]);
    const t = parseFloat(t1[1]);
    const exp = v * t;
    return near(answer[0], exp) ? {ok:true} : {ok:false, fix: [round(exp)]};
  }
  
  const d1 = stem.match(/行驶了(\d+(?:\.\d+)?)公里|相距(\d+(?:\.\d+)?)公里|总路程[=为]?([\d.]+)公里/);
  const t2 = stem.match(/用了([\d.]+)小时|([\d.]+)小时后/);
  const askSpeed = /速度(是多少|为多少)|平均速度/.test(stem);
  if(d1 && t2 && askSpeed){
    const d = parseFloat(d1[1] || d1[2] || d1[3]);
    const t = parseFloat(t2[1] || t2[2]);
    const exp = d / t;
    return near(answer[0], exp) ? {ok:true} : {ok:false, fix: [round(exp)]};
  }
  
  const v2 = stem.match(/每小时(\d+(?:\.\d+)?)公里/);
  const d2 = stem.match(/(\d+(?:\.\d+)?)公里/);
  const askTime = /多长时间|需要.*?小时|用了.*?小时/.test(stem);
  if(v2 && d2 && askTime){
    const v = parseFloat(v2[1]);
    const d = parseFloat(d2[1]);
    const exp = d / v;
    return near(answer[0], exp) ? {ok:true} : {ok:false, fix: [round(exp)]};
  }
  
  const vMin = stem.match(/每分钟(\d+(?:\.\d+)?)米/);
  const tMin = stem.match(/([\d.]+)分钟/);
  const askDistM = /多少米|一共.*?多少米/.test(stem);
  if(vMin && tMin && askDistM){
    const v = parseFloat(vMin[1]);
    const t = parseFloat(tMin[1]);
    const exp = v * t;
    return near(answer[0], exp) ? {ok:true} : {ok:false, fix:[round(exp)]};
  }
  
  const vSec = stem.match(/每秒(\d+(?:\.\d+)?)米/);
  const dM = stem.match(/(\d+(?:\.\d+)?)米/);
  const askTimeSec = /多长时间|需要.*?秒|用了.*?秒/.test(stem);
  if(vSec && dM && askTimeSec){
    const v = parseFloat(vSec[1]);
    const d = parseFloat(dM[1]);
    const exp = d / v;
    return near(answer[0], exp) ? {ok:true} : {ok:false, fix:[round(exp)]};
  }
  
  const train = stem.match(/火车长(\d+(?:\.\d+)?)米/);
  const bridge = stem.match(/桥.*?长(\d+(?:\.\d+)?)米/);
  const vSec2 = stem.match(/每秒(\d+(?:\.\d+)?)米/);
  const askBridgeTime = /通过.*?需要.*?秒|通过.*?多长时间|过桥.*?多长时间/.test(stem);
  if(train && bridge && vSec2 && askBridgeTime){
    const L = parseFloat(train[1]);
    const B = parseFloat(bridge[1]);
    const v = parseFloat(vSec2[1]);
    const exp = (L + B) / v;
    return near(answer[0], exp) ? {ok:true} : {ok:false, fix:[round(exp)]};
  }
  
  const vHourUnit = stem.match(/每小时(\d+(?:\.\d+)?)\s*(?:个|件|字|台|米)/);
  const tHour = stem.match(/([\d.]+)小时/);
  const askCount = /多少(?:个|件|字|台|米)|共(?:有)?(?:\d+)?(?:个|件|字|台|米)/.test(stem);
  if(vHourUnit && tHour && askCount){
    const v = parseFloat(vHourUnit[1]);
    const t = parseFloat(tHour[1]);
    const exp = v * t;
    return near(answer[0], exp) ? {ok:true} : {ok:false, fix:[round(exp)]};
  }
  
  const dCount = stem.match(/(?:共有|共)(\d+(?:\.\d+)?)\s*(?:个|件|字|台|米)/);
  const askHour = /(?:(?:需要|用|用了)多少小时|几小时)/.test(stem);
  if(vHourUnit && dCount && askHour){
    const v = parseFloat(vHourUnit[1]);
    const d = parseFloat(dCount[1]);
    const exp = d / v;
    return near(answer[0], exp) ? {ok:true} : {ok:false, fix:[round(exp)]};
  }
  
  return null;
}

// 10. 几何计算 + 28. 面积计算
function verifyRectangle(stem, answer){
  const hasArea = /面积/.test(stem);
  const hasPeri = /周长/.test(stem);
  const m = stem.match(/长.*?(\d+(?:\.\d+)?)\s*(?:厘米|米|cm|m).*?宽.*?(\d+(?:\.\d+)?)\s*(?:厘米|米|cm|m)/);
  if(!m) return null;
  const L = parseFloat(m[1]);
  const W = parseFloat(m[2]);
  if(hasArea){
    const exp = L * W; return near(answer[0], exp) ? {ok:true} : {ok:false, fix:[round(exp)]};
  }
  if(hasPeri){
    const exp = 2*(L+W); return near(answer[0], exp) ? {ok:true} : {ok:false, fix:[round(exp)]};
  }
  return null;
}

// 一元一次方程：用答案回代
function verifyLinearEquation(stem, answer){
  const m = stem.match(/解方程：?\s*([^\n]+)/);
  if(!m) return null;
  const eq = m[1].replace(/（/g,'(').replace(/）/g,')');
  if(!Array.isArray(answer) || answer.length===0) return null;
  const x = Number(answer[0]);
  if(!isFinite(x)) return null;
  const sides = eq.split('='); if(sides.length!==2) return null;
  try{
    const L = evalExpr(sides[0], x);
    const R = evalExpr(sides[1], x);
    return near(L,R) ? {ok:true} : {ok:false};
  }catch{ return null; }
}

function evalExpr(expr, x){
  const safe = expr.replace(/x/g, `(${x})`).replace(/[^0-9+\-*/(). ]/g,'');
  return Function(`return (${safe})`)();
}

// 3. 年龄问题
function verifyAge(stem, answer){
  // 年龄差不变原理
  const now1 = stem.match(/今年.*?(\d+)岁|现在.*?(\d+)岁|爸爸.*?(\d+)岁|妈妈.*?(\d+)岁|哥哥.*?(\d+)岁|姐姐.*?(\d+)岁/);
  const now2 = stem.match(/儿子.*?(\d+)岁|弟弟.*?(\d+)岁|妹妹.*?(\d+)岁|小明.*?(\d+)岁/);
  const years = stem.match(/(\d+)年[前后]/);

  if(now1 && now2 && years){
    const age1 = parseFloat(now1[1] || now1[2] || now1[3]);
    const age2 = parseFloat(now2[1]);
    const y = parseFloat(years[1]);
    const isBefore = /年前/.test(stem);

    if(/多少岁/.test(stem)){
      const exp1 = isBefore ? age1 - y : age1 + y;
      const exp2 = isBefore ? age2 - y : age2 + y;
      if(Array.isArray(answer) && answer.length >= 2){
        if(near(answer[0], exp1) && near(answer[1], exp2)) return {ok:true};
        if(near(answer[0], exp2) && near(answer[1], exp1)) return {ok:true};
        return {ok:false, fix:[round(exp1), round(exp2)]};
      }
    }
  }
  return null;
}

// 14. 百分数应用题
function verifyPercent(stem, answer){
  // 打折问题：原价×折扣=现价
  const price = stem.match(/原价[是为]?(\d+(?:\.\d+)?)元|定价[是为]?(\d+(?:\.\d+)?)元/);
  const discount = stem.match(/(\d+)折/);
  if(price && discount){
    const P = parseFloat(price[1] || price[2]);
    const D = parseFloat(discount[1]) / 10;
    const exp = P * D;
    if(/现价|售价|实际/.test(stem)){
      return near(answer[0], exp) ? {ok:true} : {ok:false, fix:[round(exp)]};
    }
  }

  // 涨跌问题：原值×(1±百分比)=新值
  const base = stem.match(/原来[是为]?(\d+(?:\.\d+)?)|去年[是为]?(\d+(?:\.\d+)?)/);
  const percent = stem.match(/增加了?(\d+(?:\.\d+)?)%|提高了?(\d+(?:\.\d+)?)%|下降了?(\d+(?:\.\d+)?)%|减少了?(\d+(?:\.\d+)?)%/);
  if(base && percent){
    const B = parseFloat(base[1] || base[2]);
    const P = parseFloat(percent[1] || percent[2] || percent[3] || percent[4]) / 100;
    const isIncrease = /增加|提高/.test(stem);
    const exp = isIncrease ? B * (1 + P) : B * (1 - P);
    if(/现在|今年/.test(stem)){
      return near(answer[0], exp) ? {ok:true} : {ok:false, fix:[round(exp)]};
    }
  }

  // 利润问题：利润=售价-成本，利润率=利润/成本
  const cost = stem.match(/成本[是为]?(\d+(?:\.\d+)?)元|进价[是为]?(\d+(?:\.\d+)?)元/);
  const profitRate = stem.match(/利润率[是为]?(\d+(?:\.\d+)?)%/);
  if(cost && profitRate){
    const C = parseFloat(cost[1] || cost[2]);
    const R = parseFloat(profitRate[1]) / 100;
    const exp = C * (1 + R);
    if(/售价|定价/.test(stem)){
      return near(answer[0], exp) ? {ok:true} : {ok:false, fix:[round(exp)]};
    }
  }

  return null;
}

// 15. 比例应用题
function verifyRatio(stem, answer){
  // 比例分配：总量按比例分配
  const total = stem.match(/总[共和](?:有|是)?(\d+(?:\.\d+)?)|一共(?:有|是)?(\d+(?:\.\d+)?)/);
  const ratio = stem.match(/按(\d+):(\d+)(?::(\d+))?的比例|比例[是为](\d+):(\d+)(?::(\d+))?/);

  if(total && ratio){
    const T = parseFloat(total[1] || total[2]);
    const r1 = parseFloat(ratio[1] || ratio[4]);
    const r2 = parseFloat(ratio[2] || ratio[5]);
    const r3 = ratio[3] || ratio[6] ? parseFloat(ratio[3] || ratio[6]) : null;

    if(r3){
      const sum = r1 + r2 + r3;
      const p1 = T * r1 / sum;
      const p2 = T * r2 / sum;
      const p3 = T * r3 / sum;
      if(Array.isArray(answer) && answer.length >= 3){
        if(near(answer[0], p1) && near(answer[1], p2) && near(answer[2], p3)) return {ok:true};
        return {ok:false, fix:[round(p1), round(p2), round(p3)]};
      }
    } else {
      const sum = r1 + r2;
      const p1 = T * r1 / sum;
      const p2 = T * r2 / sum;
      if(Array.isArray(answer) && answer.length >= 2){
        if(near(answer[0], p1) && near(answer[1], p2)) return {ok:true};
        if(near(answer[0], p2) && near(answer[1], p1)) return {ok:true};
        return {ok:false, fix:[round(p1), round(p2)]};
      }
    }
  }

  // 正比例：y=kx
  const x1 = stem.match(/当.*?[是为](\d+(?:\.\d+)?)时/);
  const y1 = stem.match(/[是为](\d+(?:\.\d+)?)/);
  const x2 = stem.match(/[是为](\d+(?:\.\d+)?)时/);
  if(x1 && y1 && x2 && /成正比/.test(stem)){
    const X1 = parseFloat(x1[1]);
    const Y1 = parseFloat(y1[1]);
    const X2 = parseFloat(x2[1]);
    const k = Y1 / X1;
    const exp = k * X2;
    return near(answer[0], exp) ? {ok:true} : {ok:false, fix:[round(exp)]};
  }

  return null;
}

// 12. 分数应用题
function verifyFraction(stem, answer){
  // 求一个数的几分之几
  const num = stem.match(/(\d+(?:\.\d+)?)(?:个|米|千克|元|人|本|棵|道|台)/);
  const frac = stem.match(/(\d+)\/(\d+)|[的占](\d+)分之(\d+)/);

  if(num && frac){
    const N = parseFloat(num[1]);
    const numerator = parseFloat(frac[1] || frac[4]);
    const denominator = parseFloat(frac[2] || frac[3]);
    const used = N * numerator / denominator;
    const remain = N - used;

    // 判断题目问的是"用去/看了"还是"还剩"
    if(/还剩|剩余|剩下/.test(stem)){
      return near(answer[0], remain) ? {ok:true} : {ok:false, fix:[round(remain)]};
    } else if(/用去|用了|看了|吃了|做对|已经|修了/.test(stem)){
      return near(answer[0], used) ? {ok:true} : {ok:false, fix:[round(used)]};
    }
  }

  return null;
}

// 42. 二元一次方程组
function verifyLinearSystem(stem, answer){
  const eq1 = stem.match(/([xy\d\s+\-=]+)/);
  const eq2 = stem.match(/([xy\d\s+\-=]+)/g);

  if(!eq2 || eq2.length < 2) return null;
  if(!Array.isArray(answer) || answer.length < 2) return null;

  const x = Number(answer[0]);
  const y = Number(answer[1]);
  if(!isFinite(x) || !isFinite(y)) return null;

  // 简单验证：回代检查
  try {
    // 这里需要更复杂的解析，暂时跳过
    return null;
  } catch {
    return null;
  }
}

// ========== 新增验证器函数 ==========

// 盈亏问题验证器
function verifyProfitLoss(stem, answer){
  const m1 = stem.match(/每人分(\d+)个.*?多(\d+)个.*?每人分(\d+)个.*?少(\d+)个/);
  if(m1){
    const [,n1,surplus,n2,shortage] = m1.map(Number);
    const people = (surplus + shortage) / (n2 - n1);
    const items = people * n1 + surplus;
    if(Number.isInteger(people) && people > 0){
      if(near(answer[0], people) && (answer.length === 1 || near(answer[1], items))){
        return {ok:true};
      }
      return {ok:false, fix: answer.length === 1 ? [people] : [people, items]};
    }
  }
  const m2 = stem.match(/每人分(\d+)个.*?剩(\d+)个.*?每人分(\d+)个.*?缺(\d+)个/);
  if(m2){
    const [,n1,surplus,n2,shortage] = m2.map(Number);
    const people = (surplus + shortage) / (n2 - n1);
    const items = people * n1 + surplus;
    if(Number.isInteger(people) && people > 0){
      if(near(answer[0], people) && (answer.length === 1 || near(answer[1], items))){
        return {ok:true};
      }
      return {ok:false, fix: answer.length === 1 ? [people] : [people, items]};
    }
  }
  return null;
}

// 植树问题验证器
function verifyTreePlanting(stem, answer){
  const m1 = stem.match(/长(\d+)米.*?每隔(\d+)米.*?两端都栽/);
  if(m1){
    const [,length,interval] = m1.map(Number);
    const trees = length / interval + 1;
    if(Number.isInteger(trees)){
      return near(answer[0], trees) ? {ok:true} : {ok:false, fix:[trees]};
    }
  }
  const m2 = stem.match(/长(\d+)米.*?每隔(\d+)米.*?两端都不栽/);
  if(m2){
    const [,length,interval] = m2.map(Number);
    const trees = length / interval - 1;
    if(Number.isInteger(trees)){
      return near(answer[0], trees) ? {ok:true} : {ok:false, fix:[trees]};
    }
  }
  const m3 = stem.match(/长(\d+)米.*?每隔(\d+)米.*?一端栽/);
  if(m3){
    const [,length,interval] = m3.map(Number);
    const trees = length / interval;
    if(Number.isInteger(trees)){
      return near(answer[0], trees) ? {ok:true} : {ok:false, fix:[trees]};
    }
  }
  const m4 = stem.match(/周长(\d+)米.*?每隔(\d+)米/);
  if(m4){
    const [,length,interval] = m4.map(Number);
    const trees = length / interval;
    if(Number.isInteger(trees)){
      return near(answer[0], trees) ? {ok:true} : {ok:false, fix:[trees]};
    }
  }
  return null;
}

// 归一问题验证器
function verifyUnitRate(stem, answer){
  const m1 = stem.match(/(\d+)个.*?用.*?(\d+).*?(\d+)个.*?用/);
  if(m1){
    const [,count1,amount1,count2] = m1.map(Number);
    const unitRate = amount1 / count1;
    const result = unitRate * count2;
    return near(answer[0], result) ? {ok:true} : {ok:false, fix:[round(result)]};
  }
  const m2 = stem.match(/(\d+)元.*?买.*?(\d+)个.*?(\d+)元.*?买/);
  if(m2){
    const [,money1,count1,money2] = m2.map(Number);
    const unitPrice = money1 / count1;
    const result = money2 / unitPrice;
    return near(answer[0], result) ? {ok:true} : {ok:false, fix:[round(result)]};
  }
  return null;
}

// 数论基础验证器
function verifyNumberTheory(stem, answer){
  const m1 = stem.match(/(\d+)是质数吗|(\d+)是不是质数/);
  if(m1){
    const num = Number(m1[1] || m1[2]);
    const isPrime = (n) => {
      if(n < 2) return false;
      for(let i = 2; i <= Math.sqrt(n); i++){
        if(n % i === 0) return false;
      }
      return true;
    };
    const result = isPrime(num);
    const expected = answer[0] === '是' || answer[0] === true || answer[0] === 1;
    return result === expected ? {ok:true} : {ok:false, fix:[result ? '是' : '不是']};
  }
  const m2 = stem.match(/(\d+)和(\d+)的最大公约数/);
  if(m2){
    const [,a,b] = m2.map(Number);
    const gcd = (x, y) => y === 0 ? x : gcd(y, x % y);
    const result = gcd(a, b);
    return near(answer[0], result) ? {ok:true} : {ok:false, fix:[result]};
  }
  const m3 = stem.match(/(\d+)和(\d+)的最小公倍数/);
  if(m3){
    const [,a,b] = m3.map(Number);
    const gcd = (x, y) => y === 0 ? x : gcd(y, x % y);
    const lcm = (x, y) => (x * y) / gcd(x, y);
    const result = lcm(a, b);
    return near(answer[0], result) ? {ok:true} : {ok:false, fix:[result]};
  }
  return null;
}

// 二次函数验证器
function verifyQuadraticFunction(stem, answer){
  const m1 = stem.match(/y\s*=\s*(-?\d+)x²\s*\+\s*(-?\d+)x\s*\+\s*(-?\d+).*?顶点/);
  if(m1){
    const [,a,b,c] = m1.map(Number);
    const x = -b / (2 * a);
    const y = a * x * x + b * x + c;
    if(Array.isArray(answer[0])){
      if(near(answer[0][0], x) && near(answer[0][1], y)){
        return {ok:true};
      }
      return {ok:false, fix:[[round(x, 2), round(y, 2)]]};
    }
  }
  const m2 = stem.match(/y\s*=\s*(-?\d+)x²\s*\+\s*(-?\d+)x\s*\+\s*(-?\d+).*?对称轴/);
  if(m2){
    const [,a,b,c] = m2.map(Number);
    const x = -b / (2 * a);
    const result = `x=${round(x, 2)}`;
    if(answer[0] === result || near(answer[0], x)){
      return {ok:true};
    }
    return {ok:false, fix:[result]};
  }
  return null;
}

// 解直角三角形验证器
function verifyRightTriangle(stem, answer){
  const m1 = stem.match(/直角三角形.*?两直角边.*?(\d+).*?(\d+).*?斜边/);
  if(m1){
    const [,a,b] = m1.map(Number);
    const c = Math.sqrt(a*a + b*b);
    return near(answer[0], c) ? {ok:true} : {ok:false, fix:[round(c, 2)]};
  }
  const m2 = stem.match(/直角三角形.*?斜边.*?(\d+).*?直角边.*?(\d+).*?另一直角边/);
  if(m2){
    const [,c,a] = m2.map(Number);
    const b = Math.sqrt(c*c - a*a);
    if(b > 0){
      return near(answer[0], b) ? {ok:true} : {ok:false, fix:[round(b, 2)]};
    }
  }
  return null;
}

// 选择验证器
function pickVerifiers(topic){
  const arr=[];
  if(/鸡兔同笼/.test(topic)) arr.push('chicken');
  if(/和差倍问题/.test(topic)) arr.push('sum-diff');
  if(/年龄问题/.test(topic)) arr.push('age');
  if(/平均数问题/.test(topic)) arr.push('average');
  if(/行程问题/.test(topic)) arr.push('distance');
  if(/工程问题/.test(topic)) arr.push('distance');
  if(/几何计算|面积计算/.test(topic)) arr.push('rectangle');
  if(/百分数应用题/.test(topic)) arr.push('percent');
  if(/比例应用题/.test(topic)) arr.push('ratio');
  if(/分数应用题/.test(topic)) arr.push('fraction');
  if(/一元一次方程/.test(topic)) arr.push('linear');
  if(/二元一次方程组/.test(topic)) arr.push('linear-system');
  // 新增验证器
  if(/盈亏问题/.test(topic)) arr.push('profit-loss');
  if(/植树问题/.test(topic)) arr.push('tree-planting');
  if(/归一问题/.test(topic)) arr.push('unit-rate');
  if(/数论基础/.test(topic)) arr.push('number-theory');
  if(/二次函数/.test(topic)) arr.push('quadratic');
  if(/解直角三角形/.test(topic)) arr.push('right-triangle');
  return arr;
}

function runVerifier(verifier, stem, answer){
  if(verifier==='chicken') return solveChickenRabbit(stem);
  if(verifier==='sum-diff') return verifySumDiff(stem, answer);
  if(verifier==='age') return verifyAge(stem, answer);
  if(verifier==='average') return verifyAverage(stem, answer);
  if(verifier==='distance') return verifyDistanceLike(stem, answer);
  if(verifier==='rectangle') return verifyRectangle(stem, answer);
  if(verifier==='percent') return verifyPercent(stem, answer);
  if(verifier==='ratio') return verifyRatio(stem, answer);
  if(verifier==='fraction') return verifyFraction(stem, answer);
  if(verifier==='linear') return verifyLinearEquation(stem, answer);
  if(verifier==='linear-system') return verifyLinearSystem(stem, answer);
  // 新增验证器
  if(verifier==='profit-loss') return verifyProfitLoss(stem, answer);
  if(verifier==='tree-planting') return verifyTreePlanting(stem, answer);
  if(verifier==='unit-rate') return verifyUnitRate(stem, answer);
  if(verifier==='number-theory') return verifyNumberTheory(stem, answer);
  if(verifier==='quadratic') return verifyQuadraticFunction(stem, answer);
  if(verifier==='right-triangle') return verifyRightTriangle(stem, answer);
  return null;
}

function processFile(fullPath, topicIndex){
  const ts = read(fullPath);
  const { name, array } = extractExportedArray(ts) || {};
  if(!name) return { skipped:true };
  const data = parseArray(array) || [];
  const topic = path.basename(fullPath, '.ts');
  const verifiers = pickVerifiers(topic);
  if(verifiers.length===0) return { skipped:true, topic, topicIndex };

  let changed=0, checked=0, errors=0, fixed=0; const issues=[];
  const fixedArr = data.map((q, i)=>{
    let verdict = null;
    for(const v of verifiers){
      verdict = runVerifier(v, q.stem||'', q.answer||[]);
      if(verdict) break;
    }
    if(!verdict) return q;

    checked++;
    if(verdict.ok===true){ return q; }

    if(verdict.c!=null && verdict.r!=null){
      const expected=[verdict.c, verdict.r];
      const ans = Array.isArray(q.answer)?q.answer:[q.answer];
      if(!(ans.length>=2 && ans[0]===expected[0] && ans[1]===expected[1])){
        const nq={...q};
        nq.answer = expected;
        nq.solution = (q.solution? (q.solution+"\n\n") : "") +
          `【自动校正】依据题干：共有头${verdict.H}个、脚${verdict.F??'?'}只 ⇒ 鸡${expected[0]}只，兔${expected[1]}只。`;
        changed++; fixed++; issues.push({index:i+1, type:'auto-fix', expect:expected, stem:q.stem});
        return nq;
      }
      return q;
    }

    if(verdict.fix && Array.isArray(verdict.fix)){
      const nq={...q};
      nq.answer = verdict.fix;
      nq.solution = (q.solution? (q.solution+"\n\n") : "") + `【自动校正】脚本核算结果：${verdict.fix.join(', ')}`;
      changed++; fixed++; issues.push({index:i+1, type:'auto-fix', expect:verdict.fix, stem:q.stem});
      return nq;
    }

    errors++; issues.push({index:i+1, type:'mismatch', stem:q.stem});
    return q;
  });

  if(changed>0){
    const rebuilt = rebuild(name, fixedArr, ts);
    write(fullPath, rebuilt);
  }
  return { topicIndex, topic, file: fullPath, total: data.length, checked, changed, errors, issues };
}

function main(){
  const summary=[];
  let topicIndex = 0;
  
  for(const topicName of TOPIC_ORDER){
    topicIndex++;
    const fileName = `${topicName}.ts`;
    let fullPath = path.join(PRIMARY_DIR, fileName);
    if(!fs.existsSync(fullPath)){
      fullPath = path.join(MIDDLE_DIR, fileName);
    }
    if(!fs.existsSync(fullPath)){
      console.log(`${topicIndex}. ${topicName} - 文件不存在`);
      continue;
    }
    
    const res = processFile(fullPath, topicIndex);
    if(res.skipped){
      console.log(`${topicIndex}. ${topicName} - 跳过（无验证规则）`);
    } else {
      summary.push(res);
      console.log(`${topicIndex}. ${topicName} - 题目:${res.total} 已判定:${res.checked} 改动:${res.changed} 未修复:${res.errors}`);
    }
  }
  
  const outDir = path.join(ROOT,'math-academy','docs'); 
  if(!fs.existsSync(outDir)) fs.mkdirSync(outDir,{recursive:true});
  const outFile = path.join(outDir, 'verify-all-topics-summary.json');
  write(outFile, JSON.stringify(summary, null, 2));
  console.log(`\n完成！报告：${outFile}`);
}

main();

